import java.util.Iterator;
import java.util.LinkedList;

public class TailEnderScheduler implements Scheduler {

	double signal_strength = 0;
	Application[] apps = null;
	int appNumber = 5;
	int slot_number = 0;
	LinkedList<DataUnit> du_list = null;

	int lastSendTime = -1;

	SignalGenerator sg = null;
	double power = 0;
	double bandwidth = 0;

	double energy_consumption = 0;
	double tail_energy_consumption = 0;
	double performance_penalty = 0;

	public TailEnderScheduler(boolean Geometric) {
		apps = new Application[appNumber];
		du_list = new LinkedList<DataUnit>();
		sg = new SignalGenerator();

		if (Geometric == true) {
			// 等比
			apps[0] = new Application(10);
			apps[1] = new Application(10);
			apps[2] = new Application(10);
			apps[3] = new Application(10);
			apps[4] = new Application(10);

		} else {
			// 反比
			apps[0] = new Application(10);
			apps[1] = new Application(10);
			apps[2] = new Application(10);
			apps[3] = new Application(10);
			apps[4] = new Application(10);
		}

	}

	public int getBandwidth() {
		return (int) (2.667 * signal_strength + 293.73);
	}

	public double getPower() {
		return -25 * signal_strength - 1030.9;

	}

	@Override
	public void begin_scheduling(int slot_number) {
		// TODO Auto-generated method stub
		this.slot_number=slot_number;
		
		for(int t=0;t<this.slot_number;t++)
		{
			signal_strength=sg.getSignal(t);
			power=getPower();
			bandwidth=getBandwidth();
			
			//每一个时隙，首先从每一个应用中获取新生成的数据单元
			DataUnit newdu1=apps[0].generateData(10, t);
			DataUnit newdu2=apps[1].generateData(200, t);
			DataUnit newdu3=apps[2].generateData(400, t);
			DataUnit newdu4=apps[3].generateData(800, t);
			DataUnit newdu5=apps[4].generateData(1600, t);
			//初始化到达时间跟延迟.如若生成的数据单元不为空，添加到队列中
			if(newdu1!=null)
			{
				newdu1.arr_time=t;
				newdu1.delay=-1;
				du_list.add(newdu1);
				newdu1.omega=160.0/ 175;
			}
			if(newdu2!=null)
			{
				newdu2.arr_time=t;
				newdu2.delay=-1;
				du_list.add(newdu2);
				newdu2.omega=8.0/175;
			}
			if(newdu3!=null)
			{
				newdu3.arr_time=t;
				newdu3.delay=-1;
				du_list.add(newdu3);
				newdu3.omega=4.0/175;
			}
			if(newdu4!=null)
			{
				newdu4.arr_time=t;
				newdu4.delay=-1;
				du_list.add(newdu4);
				newdu4.omega=2.0/ 175;
			}
			if(newdu5!=null)
			{
				newdu5.arr_time=t;
				newdu5.delay=-1;
				du_list.add(newdu5);
				newdu5.omega=1.0/ 175;
			}
			
			//更新每一个数据单元的时延
			for(DataUnit du:du_list)
			{
				du.delay++;
			}
			
			if(du_list.size()>0&&bandwidth>0)
			{
			if((t-lastSendTime)<7)
			{
			//如果距离上一次发送数据结束不到7s的时间，那么此时发送数据可以减少tail
			//因此发送数据
				tail_energy_consumption+=getTailPower(t);
				
				Iterator<DataUnit> iter=du_list.iterator();
				
				int allocated_bandwidth=(int) bandwidth;
				

				
				while(iter.hasNext())
				{
					DataUnit du=iter.next();
					//根据剩余的带宽情况来发送数据单元
					if(du.data.length<=allocated_bandwidth)
					{		
						//剩下的带宽足够发送整个数据单元
						/**
						 * 发送数据
						 */
						energy_consumption+=power*(du.data.length*1.0/bandwidth);//更新能耗
//						System.out.println(""+t+"s: "+energy_consumption+" "+allocated_bandwidth+" "+power+" "+bandwidth+" "+signal_strength);
						performance_penalty+=du.omega*du.data.length*Penalty.f(du.delay, du.bound);
						allocated_bandwidth-=du.data.length;
						iter.remove();
						lastSendTime=t;		
					}
					else
					{
						//剩下的带宽不足以发送整个数据单元
						/**
						 * 发送数据
						 */
						energy_consumption+=power*(allocated_bandwidth*1.0/bandwidth);
//						System.out.println(""+t+"s: "+energy_consumption+" "+allocated_bandwidth+" "+power+" "+bandwidth+" "+signal_strength);
						performance_penalty+=du.omega*allocated_bandwidth*Penalty.f(du.delay, du.bound);
						lastSendTime=t;
						du.data=new byte[du.data.length-allocated_bandwidth];
						allocated_bandwidth=0;
						break;
					}
				}
			}
			else		
			{
				//依此遍历每一个在队列中的数据单元，如果有到达deadline的数据单元，则发送数据		
				int allocated_bandwidth=(int)bandwidth;
				boolean send=false;
				//查看是否存在到达了deadline的数据单元
				for(DataUnit du : du_list)
				{
					if((t-du.arr_time)>=du.bound)
					{
						send=true;
						lastSendTime=t;
						tail_energy_consumption+=getTailPower(t);
						break;
					}
				}
				Iterator<DataUnit> it=du_list.iterator();
				if(send==true)
				{
					//存在超过了deadline的数据单元，发送数据
					while(it.hasNext())
					{
						DataUnit du=it.next();
						
						//根据剩余的带宽情况来发送数据单元
						if(du.data.length<=allocated_bandwidth)
						{
							
							//剩下的带宽足够发送整个数据单元
							/**
							 * 发送数据
							 */
							energy_consumption+=power*(du.data.length*1.0/bandwidth);//更新能耗
//							System.out.println(""+t+"s: "+energy_consumption+" "+allocated_bandwidth+" "+power+" "+bandwidth+" "+signal_strength);
							performance_penalty+=du.omega*du.data.length*Penalty.f(du.delay, du.bound);
							allocated_bandwidth-=du.data.length;
							it.remove();
							lastSendTime=t;
							
						}
						else
						{
							//剩下的带宽不足以发送整个数据单元
							/**
							 * 发送数据
							 */
							energy_consumption+=power*(allocated_bandwidth*1.0/bandwidth);
//							System.out.println(""+t+"s: "+energy_consumption+" "+allocated_bandwidth+" "+power+" "+bandwidth+" "+signal_strength);
							performance_penalty+=du.omega*allocated_bandwidth*Penalty.f(du.delay, du.bound);
							lastSendTime=t;
							du.data=new byte[du.data.length-allocated_bandwidth];
							allocated_bandwidth=0;
							break;
						}
						
					}
					
				}
				
			}
			
			}
			
		}
		
		System.out.print(""+(energy_consumption+tail_energy_consumption)+",");
		System.out.print(""+performance_penalty+"");
		System.out.println();
	}
	
	@Override
	public void setV(double v) {
		// TODO Auto-generated method stub

	}

	
	@Override
	public double getV() {
		// TODO Auto-generated method stub
		return 0;
	}

	
	public double getTailPower(int t) {
		if (lastSendTime == -1)
			return 0;
		if ((t - lastSendTime) > 7) {
			// 计算完整的一个tail
			return 732 * 3 + 388 * 4;
		} else if ((t - lastSendTime) > 3) {
			return (t - lastSendTime - 3 - 1) * 388 + 732 * 3;
		} else {
			return (t - lastSendTime - 1) * 732;
		}
	}

}
